package study.javaee.practice.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.URLUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import study.javaee.practice.common.exception.Throws;
import study.javaee.practice.dao.UserDao;
import study.javaee.practice.entity.User;
import study.javaee.practice.entity.UserDetailsEntity;
import study.javaee.practice.service.AuthService;
import study.javaee.practice.service.EmailService;
import study.javaee.practice.service.UserCacheService;
import study.javaee.practice.service.UserService;
import study.javaee.practice.utils.security.MyPasswordEncoder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.util.Objects;

@Component
public class AuthServiceImpl implements AuthService {

    private final LineCaptcha lineCaptcha;
    UserCacheService userCacheService;
    UserService userService;
    final EmailService emailService;
    final MyPasswordEncoder passwordEncoder;
    final UserDao userDao;

    @Autowired
    AuthServiceImpl(UserCacheService userCacheService, UserService userService, EmailService emailService,
                    MyPasswordEncoder passwordEncoder, UserDao userDao){
        this.userCacheService = userCacheService;
        this.userService = userService;
        this.emailService = emailService;
        this.passwordEncoder = passwordEncoder;
        this.userDao = userDao;
        lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100);
    }

    private String requestImgVerCode(HttpServletRequest request, String usage) {
        String code = RandomUtil.randomString(4);
        Image image = lineCaptcha.createImage(code);
        final ByteArrayOutputStream out = new ByteArrayOutputStream();
        ImgUtil.writePng(image, out);
        String b64Img = URLUtil.getDataUriBase64("image/png", Base64.encode(out.toByteArray()) );
        HttpSession session = request.getSession();
        session.setAttribute(usage + "_imgCode", code);
        return b64Img;
    }

    private void ensureImgCode(String usage, String code, HttpServletRequest request){
        HttpSession session = request.getSession();
        String attr = usage + "_imgCode";
        String realCode = session.getAttribute(attr).toString();
        if (realCode==null){
            Throws.clientFailed("验证码已过期");
        }
        if (!Objects.equals(realCode, code)){
            Throws.clientFailed("验证码错误");
        }
    }

    public String requestImgLoginVerCode(HttpServletRequest request){
        return requestImgVerCode(request, "login");
    }

    void requestEmailVerCode(String email, String usage, String preContent){
        if (userCacheService.getEmailVerCode(email, usage)!=null){
            Throws.clientFailed("请求过于频繁!");
        }
        String code = RandomUtil.randomNumbers(6);
        userCacheService.setEmailVerCode(email,usage , code);
        emailService.sendEmail(email, preContent + code);
    }

    @Override
    public void requestLoginEmailVerCode(String email) {
        requestEmailVerCode(email, "login", "您的登录验证码是：");
    }

    @Override
    public void requestRegisterEmailVerCode(String email) {
        if (userService.hasUser(email)){
            Throws.clientFailed("邮箱账号已经存在");
        }
        requestEmailVerCode(email, "register", "您的注册验证码是：");
    }

    @Override
    public void requestFindPwdEmailVerCode(String email) {
        requestEmailVerCode(email, "find_pwd", "您正在找回密码，您的验证码是：");
    }

    private void ensureEmailCode(String email, String usage, String code) {
        String realCode = userCacheService.getEmailVerCode(email, usage);
        if (realCode==null){
            Throws.clientFailed("验证码已过期");
        }
        if (!Objects.equals(realCode, code)){
            Throws.clientFailed("验证码错误");
        }
        //删除邮箱验证码缓存
        userCacheService.deleteEmailVerCode(email, usage);
    }

    @Override
    public User logIn(String email, String password, String verCode, HttpServletRequest request) {
        ensureImgCode("login",verCode , request);
        User user = userService.getUserByEmail(email);
        password = passwordEncoder.encode(password, email);
        if (user == null|| !Objects.equals(password, user.getPassword())){
            Throws.clientFailed("账号或密码错误");
        }
        // 将用户权限保存到spring security 上下文
        user.setPassword(null);
        UserDetailsEntity userDetails = new UserDetailsEntity(user);
        UsernamePasswordAuthenticationToken authentication =
                new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
        return user;  // 登录成功
    }

    @Override
    public User logIn(String email, String password, String verCode, HttpServletRequest request, boolean remember) {
        User user = logIn(email, password, verCode, request);
        if (remember){
            request.getSession().setMaxInactiveInterval(3*24*60);
        }
        return user;
    }

    @Override
    public void register(User user, String verCode) {
        ensureEmailCode(user.getEmail(), "register", verCode);
        user.setId(null);
        user.setType(1);
        userService.addUser(user);
        user.setPassword(null);
        UserDetailsEntity userDetails = new UserDetailsEntity(user);
        UsernamePasswordAuthenticationToken authentication =
                new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }

    @Override
    public void logout(HttpServletRequest request) {
        User user = userService.getCurrentUser( );
        if (user == null){
            return;
        }
        // 1.从缓存中删除当前用户  2.使session失效
        userCacheService.deleteUser(user.getEmail());
        request.getSession().invalidate();
    }

    @Override
    public void findUserPassword(String email, String password, String code) {
        ensureEmailCode(email, "find_pwd", code);
        User user = userService.getUserByEmail(email);
        user.setPassword(password);
        userService.updateUserById(user, user.getId());
    }

}
